#include <appkit/basetype.h>
#include <appkit/console.h>
#include <appkit/datetime.h>
#include <appkit/serial.h>
#include <appkit/strutil.h>
#include <appkit/thread.h>
#include <appkit/tracer.h>

using namespace appkit;  // NOLINT
void test_serial() {
    TRACE_INFO("input serial device:");
    ConsoleIn ci;
    ci.waitInput();
    auto deviceName = ci.asString();

    TRACE_INFO("input serial baudrate:");
    ci.waitInput();
    auto baudrate = ci.asInt();

    TRACE_INFO("open serial: %s, baudrate: %d", deviceName.data(), baudrate);
    SerialPort serial;
    serial.setAttribute(SerialPort::ATTR_BAUDRATE, baudrate);
    if (!serial.open(deviceName, IO_MODE_RDWR_ONLY)) {
        TRACE_ERR("open serial error!");
        return;
    }

    // 0xFE + 序号(0~200) +数据(0x00 0x01 ... 0x7F) + 0xFF
    uint64 frameIndex = 0;
    std::string recvBuffer;
    Time startTime = Time::fromMono();
    Time lastTime = startTime;
    uint8 sequence = 0xFF;
    for (;;) {
        char buf[512] = {0};
        int len = serial.recvData(buf, sizeof(buf), 1000000);
        if (len <= 0) {
            TRACE_ERR("No Serial Data Recieved!");
            continue;
        }

        recvBuffer.append(std::string(buf, len));
        while (recvBuffer.size() > 0) {
            // 找帧头
            auto startPos = recvBuffer.find('\xFE', 0);
            if (startPos < 0) {
                TRACE_ERR("1-invalid packet:[%s]",
                          CSTR(StrUtil::hexVisualize(recvBuffer)));
                recvBuffer.clear();
                continue;
            }
            // 找帧尾
            auto endPos = recvBuffer.find('\xFF', startPos + 1);
            if (endPos < 0) {
                if (recvBuffer.size() > 1024) {
                    TRACE_ERR("2-invalid packet:[%s]",
                              CSTR(StrUtil::hexVisualize(recvBuffer)));
                    recvBuffer.clear();
                    continue;
                }
                break;
            }

            // 找到一帧
            auto frame = recvBuffer.substr(startPos + 1, endPos - startPos - 1);
            recvBuffer.erase(0, endPos + 1);
            if (frame.size() != 0x81) {
                TRACE_ERR("3-invalid packet:[%s]",
                          CSTR(StrUtil::hexVisualize(frame)));
                continue;
            }
            // 判断帧间隔是否大于10ms
            auto interval = Time::usSinceMono(lastTime);
            if (interval > 10000) {
                TRACE_WARN("frame interval: %llu", interval);
            }
            TRACE_DBG("frame index: %llu", frameIndex++);
            lastTime = Time::fromMono();

            if (frameIndex % 1000 == 0) {
                auto total = Time::usSinceMono(startTime);
                auto secs = static_cast<double>(total * 0.000001);
                auto fps = frameIndex / secs;
                TRACE_INFO("total time: %f s, frames: %llu, average fps: %f",
                           secs, frameIndex, fps);
            }

            if (sequence == 0xFF) {
                sequence = frame[0];
            } else {
                uint8 idx = frame[0];
                if ((sequence + 1) % 200 != idx) {
                    TRACE_WARN("sequence error, last: %d, curr:%d", sequence,
                               idx);
                }
                sequence = idx;
            }

            for (auto i = 1; i < frame.size(); i++) {
                if (frame[i] != i - 1) {
                    TRACE_ERR("4-invalid packet:[%s]",
                              CSTR(StrUtil::hexVisualize(frame)));
                    break;
                }
            }
        }
    }
}
